﻿#region

using System;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using HouseHoldBudget.Core.Configuration;

#endregion

namespace HouseHoldBudget.Core.Infrastructure
{
    /// <summary>
    ///   Provides access to the singleton instance of the HouseHoldBudget engine.
    /// </summary>
    public class EngineContext
    {
        #region Class Properties

        /// <summary>
        ///   Gets the singleton HouseHoldBudget engine used to access HouseHoldBudget services.
        /// </summary>
        public static IEngine Current
        {
            get
            {
                if (Singleton<IEngine>.Instance == null)
                {
                    Initialize(false);
                }
                return Singleton<IEngine>.Instance;
            }
        }

        #endregion

        #region Class Methods

        /// <summary>
        ///   Creates a factory instance and adds a http application injecting facility.
        /// </summary>
        /// <returns> A new factory </returns>
        public static IEngine CreateEngineInstance(HouseHoldBudgetConfig config)
        {
            if (config != null && !string.IsNullOrEmpty(config.EngineType))
            {
                var engineType = Type.GetType(config.EngineType);
                if (engineType == null)
                    throw new ConfigurationErrorsException("The type '" + engineType +
                                                           "' could not be found. Please check the configuration at /configuration/nop/engine[@engineType] or check for missing assemblies.");
                if (!typeof (IEngine).IsAssignableFrom(engineType))
                    throw new ConfigurationErrorsException("The type '" + engineType +
                                                           "' doesn't implement 'HouseHoldBudget.Core.Infrastructure.IEngine' and cannot be configured in /configuration/nop/engine[@engineType] for that purpose.");
                return Activator.CreateInstance(engineType) as IEngine;
            }

            return new DependencyEngine();
        }

        /// <summary>
        ///   Initializes a static instance of the HouseHoldBudget factory.
        /// </summary>
        /// <param name="forceRecreate"> Creates a new factory instance even though the factory has been previously initialized. </param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static IEngine Initialize(bool forceRecreate)
        {
            if (Singleton<IEngine>.Instance == null || forceRecreate)
            {
                var config = ConfigurationManager.GetSection("HouseHoldBudgetConfig") as HouseHoldBudgetConfig;
                Debug.WriteLine("Constructing engine " + DateTime.Now);
                Singleton<IEngine>.Instance = CreateEngineInstance(config);
                Debug.WriteLine("Initializing engine " + DateTime.Now);
                Singleton<IEngine>.Instance.Initialize(config);
            }
            return Singleton<IEngine>.Instance;
        }

        /// <summary>
        ///   Sets the static engine instance to the supplied engine. Use this method to supply your own engine implementation.
        /// </summary>
        /// <param name="engine"> The engine to use. </param>
        /// <remarks>
        ///   Only use this method if you know what you're doing.
        /// </remarks>
        public static void Replace(IEngine engine)
        {
            Singleton<IEngine>.Instance = engine;
        }

        #endregion
    }
}